<!DOCTYPE html><html lang="zh-CN"><head><meta name="generator" content="Hexo 3.8.0"><meta name="google-site-verification" content="wD1H9sqEoDWmIBFt7TjlgbVqcJqiqpwR2Wq7_bvEHcE"><meta name="baidu-site-verification" content="RZErJH3v0Z"><meta charset="utf-8"><link rel="icon" href="/css/images/my_logo.png" type="image/x-icon"><title>Tomcat源码分析之启动流程分析 | ArtIsLong的博客</title><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="description" content="前面的博客介绍了Tomcat的整个架构及各个配置文件及目录的作用，接下来就对Tomcat的源码进行分析了。"><meta name="keywords" content="Tomcat"><meta property="og:type" content="article"><meta property="og:title" content="Tomcat源码分析之启动流程分析"><meta property="og:url" content="/2018/03/21/Tomcat源码分析之启动流程分析/index.html"><meta property="og:site_name" content="ArtIsLong的博客"><meta property="og:description" content="前面的博客介绍了Tomcat的整个架构及各个配置文件及目录的作用，接下来就对Tomcat的源码进行分析了。"><meta property="og:locale" content="zh-CN"><meta property="og:image" content="https://github.com/ArtIsLong/apache-tomcat-8.5.16-src/blob/master/resources/images/tomcat%E6%95%B4%E4%BD%93%E7%BB%93%E6%9E%84.png?raw=true"><meta property="og:image" content="https://raw.githubusercontent.com/ArtIsLong/apache-tomcat-8.5.16-src/master/resources/images/tomcat-startup.gif"><meta property="og:image" content="https://github.com/ArtIsLong/apache-tomcat-8.5.16-src/blob/master/resources/images/tomcat%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90.png?raw=true"><meta property="og:image" content="https://artislong.oss-cn-hangzhou.aliyuncs.com/images/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B71.png"><meta property="og:updated_time" content="2019-11-05T03:34:51.402Z"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Tomcat源码分析之启动流程分析"><meta name="twitter:description" content="前面的博客介绍了Tomcat的整个架构及各个配置文件及目录的作用，接下来就对Tomcat的源码进行分析了。"><meta name="twitter:image" content="https://github.com/ArtIsLong/apache-tomcat-8.5.16-src/blob/master/resources/images/tomcat%E6%95%B4%E4%BD%93%E7%BB%93%E6%9E%84.png?raw=true"><link rel="alternate" href="/atom.xml" title="ArtIsLong的博客" type="application/atom+xml"><link rel="stylesheet" href="/libs/font-awesome5/css/fontawesome.min.css"><link rel="stylesheet" href="/libs/font-awesome5/css/fa-brands.min.css"><link rel="stylesheet" href="/libs/font-awesome5/css/fa-solid.min.css"><link rel="stylesheet" href="/libs/open-sans/styles.css"><link rel="stylesheet" href="/libs/source-code-pro/styles.css"><link rel="stylesheet" href="/css/style.css"><script src="/libs/jquery/2.1.3/jquery.min.js"></script><link rel="stylesheet" href="/libs/lightgallery/css/lightgallery.min.css"><link rel="stylesheet" href="/libs/justified-gallery/justifiedGallery.min.css"><script>var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="//hm.baidu.com/hm.js?b59777544dd5d59ce94e191bac62427c";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script><script>(adsbygoogle=window.adsbygoogle||[]).push({google_ad_client:"ca-pub-4444107320537106",enable_page_level_ads:!0})</script></head></html><body><div id="container"><header id="header"><div id="header-main" class="header-inner"><div class="outer"><a href="/" id="logo"><i class="logo"></i> <span class="site-title">ArtIsLong的博客</span></a><nav id="main-nav"> <a class="main-nav-link" href="/.">首页</a> <a class="main-nav-link" href="/archives">归档</a> <a class="main-nav-link" href="/books">书架</a> <a class="main-nav-link" href="/about">关于我</a></nav><nav id="sub-nav"><div class="profile" id="profile-nav"> <a id="profile-anchor" href="javascript:;"><img class="avatar" src="/css/images/head.png"><i class="fas fa-caret-down"></i></a></div></nav><div id="search-form-wrap"><form class="search-form"> <input type="text" class="ins-search-input search-form-input" placeholder="搜索"> <button type="submit" class="search-form-submit"></button></form><div class="ins-search"><div class="ins-search-mask"></div><div class="ins-search-container"><div class="ins-input-wrapper"> <input type="text" class="ins-search-input" placeholder="想要查找什么..."><span class="ins-close ins-selectable"><i class="fas fa-times-circle"></i></span></div><div class="ins-section-wrapper"><div class="ins-section-container"></div></div></div></div><script>window.INSIGHT_CONFIG={TRANSLATION:{POSTS:"文章",PAGES:"页面",CATEGORIES:"分类",TAGS:"标签",UNTITLED:"(未命名)"},ROOT_URL:"/",CONTENT_URL:"/content.json"}</script><script src="/js/insight.js"></script></div></div></div><div id="main-nav-mobile" class="header-sub header-inner"><table class="menu outer"><tr><td><a class="main-nav-link" href="/.">首页</a></td><td><a class="main-nav-link" href="/archives">归档</a></td><td><a class="main-nav-link" href="/books">书架</a></td><td><a class="main-nav-link" href="/about">关于我</a></td><td><div class="search-form"> <input type="text" class="ins-search-input search-form-input" placeholder="搜索"></div></td></tr></table></div></header><div class="outer"><aside id="profile" class="profile-fixed"><div class="inner profile-inner"><div class="base-info profile-block"> <a href="/"><img id="avatar" src="/css/images/head.png"></a><h2 id="name">ArtIsLong</h2><h3 id="title">不吹牛，不装逼，只做最单纯的技术分享</h3><span id="location"><i class="fas fa-map-marker-alt" style="padding-right:5px"></i> Shanghai, China</span> <a id="follow" target="_blank" href="https://github.com/ArtIsLong">关注我</a></div><div class="article-info profile-block"><div class="article-info-block"> 39 <span>文章</span></div><div class="article-info-block"> 30 <span>标签</span></div></div><div class="profile-block social-links"><table><tr><td><a href="http://github.com/ArtIsLong" target="_blank" title="Github" class="tooltip"><i class="fab fa-github"></i></a></td><td> <a href="https://gitee.com/artislong" target="_blank" title="Gitee" class="tooltip"><i class="fab"><img src="https://gitee.com/artislong/artislong/widgets/widget_5.svg" style="height:25px;margin-bottom:-5px"></i></a></td><td> <a href="https://www.jianshu.com/u/46d989a94f20" target="_blank" title="简书" class="tooltip"><i class="fab"><span style="height:25px;margin-bottom:-5px;color:#ff8c00">简</span></i></a></td><td> <a href="mailto:chenmin049@163.com" target="_blank" title="E-Mail" class="tooltip"><i class="fab"><span style="height:25px;width:20px;margin-bottom:-5px;color:#1e90ff;font-size:16px">Mail</span></i></a></td><td><a href="/atom.xml" target="_blank" title="RSS" class="tooltip"><i class="fas fa-rss"></i></a></td></tr></table></div></div></aside><section id="main"><article id="post-Tomcat源码分析之启动流程分析" class="article article-type-post" itemscope="" itemprop="blogPost"><div class="article-inner"><header class="article-header"><h1 class="article-title" itemprop="name"> Tomcat源码分析之启动流程分析</h1><div class="article-meta"><div class="article-date"><i class="fas fa-calendar-alt"></i> <a href="/2018/03/21/Tomcat源码分析之启动流程分析/"><time datetime="2018-03-21T15:43:07.000Z" itemprop="datePublished">2018-03-21 23:43:07</time></a></div><div class="article-category"><i class="fas fa-folder"></i> <a class="article-category-link" href="/categories/Tomcat/">Tomcat</a></div><div class="article-tag"><i class="fas fa-tag"></i> <a class="tag-link" href="/tags/Tomcat/">Tomcat</a></div><div style="font-size:12px"><span id="busuanzi_container_page_pv">阅读次数：<span id="busuanzi_value_page_pv"></span></span></div></div></header><div class="article-entry" itemprop="articleBody"><div id="toc" class="toc-article"> <strong class="toc-title">文章目录</strong><ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#Tomcat源码调试环境准备"><span class="toc-number">1.</span> <span class="toc-text">Tomcat源码调试环境准备</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Tomcat-Server的组成"><span class="toc-number">2.</span> <span class="toc-text">Tomcat Server的组成</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#整体说明"><span class="toc-number">2.1.</span> <span class="toc-text">整体说明</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#各组件详解"><span class="toc-number">2.2.</span> <span class="toc-text">各组件详解</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#源码分析"><span class="toc-number">3.</span> <span class="toc-text">源码分析</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#启动总体流程"><span class="toc-number">3.1.</span> <span class="toc-text">启动总体流程</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#启动流程详解"><span class="toc-number">3.2.</span> <span class="toc-text">启动流程详解</span></a></li></ol></li></ol><li class="toc-item toc-level-2"><a class="toc-link" href="#参考书籍"><span class="toc-number"></span> <span class="toc-text">参考书籍</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#推荐博客"><span class="toc-number"></span> <span class="toc-text">推荐博客</span></a></li></div><p>前面的博客介绍了Tomcat的整个架构及各个配置文件及目录的作用，接下来就对Tomcat的源码进行分析了。<a id="more"></a></p><h3 id="Tomcat源码调试环境准备"><a href="#Tomcat源码调试环境准备" class="headerlink" title="Tomcat源码调试环境准备"></a>Tomcat源码调试环境准备</h3><p>首先下载Tomcat源码，读者可自行去<a href="http://tomcat.apache.org/" target="_blank" rel="noopener">Tomcat官网</a> 下载，若执行力差的同学也可直接从<a href="https://github.com/ArtIsLong/apache-tomcat-8.5.16-src.git" target="_blank" rel="noopener">此处</a>pull。</p><p>Tomcat源码导入到开发工具中的方法有多种，笔者采用最直接的方式，解压源码包后直接导入到开发工具中，导入之后的源码并不能直接运行，还需要几个依赖包，读者可从<a href="https://github.com/ArtIsLong/apache-tomcat-8.5.16-src.git" target="_blank" rel="noopener">此处</a>的lib目录下获取，也可自行搜集。</p><p>找好依赖包也并不能让Tomcat源码正常运行，还需要为Bootstrap这个启动类增加几个启动参数。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">-Dcatalina.home=/Users/chenmin/GitHub/tomcat</span><br><span class="line">-Dcatalina.base=/Users/chenmin/GitHub/tomcat</span><br><span class="line">-Djava.endorsed.dirs=/Users/chenmin/GitHub/tomcat/endorsed</span><br><span class="line">-Djava.io.tmpdir=/Users/chenmin/GitHub/tomcat/temp</span><br><span class="line">-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager</span><br><span class="line">-Djava.util.logging.config.file=/Users/chenmin/GitHub/tomcat/conf/logging.properties</span><br></pre></td></tr></table></figure><p>上面的参数具体代表的意思就不一一详述了，其实光看名字就知道都是干嘛用的了。</p><p>以上准备步骤做好之后，就可以直接运行Bootstrap类，运行Tomcat源码进行调试了。</p><h3 id="Tomcat-Server的组成"><a href="#Tomcat-Server的组成" class="headerlink" title="Tomcat Server的组成"></a>Tomcat Server的组成</h3><h4 id="整体说明"><a href="#整体说明" class="headerlink" title="整体说明"></a>整体说明</h4><p>在上面对配置文件的说明中，通过server.xml的解释，我们知道server.xml中最顶级的元素是server，而server.xml中的每一个元素我们都可以把它看做是Tomcat中的某一个部分。所以我们可以参照着server.xml来分析源码。</p><p>Tomcat最顶层的容器叫Server，它代表着整个Tomcat服务器。Server中至少要包含一个Service来提供服务。Service包含两部分：Connector和Container。Connector负责网络连接，request/response的创建，并对Socket和request、response进行转换等，Container用于封装和管理Servlet，并处理具体的request请求。</p><p>一个Tomcat中只有一个Server，一个Server可以有多个Service来提供服务，一个Service只有一个Container，但是可以有多个Connector（一个服务可以有多个连接）。</p><p><img src="https://github.com/ArtIsLong/apache-tomcat-8.5.16-src/blob/master/resources/images/tomcat%E6%95%B4%E4%BD%93%E7%BB%93%E6%9E%84.png?raw=true" alt="tomcat整体结构"></p><h4 id="各组件详解"><a href="#各组件详解" class="headerlink" title="各组件详解"></a>各组件详解</h4><p>可结合conf/配置文件说明中的server.xml的说明来看</p><ul><li><p>Server</p><p>Server代表整个Servlet容器</p></li><li><p>Service</p><p>Service是由一个或多个Connector以及一个Engine，负责处理所有Connector所获得的客户请求的集合。</p></li><li><p>Connector</p><p>Connector将在某个指定端口上侦听客户请求，并将获得的请求交给Engine来处理，从Engine处获得回应并返回给客户端。</p><p>Tomcat有两个默认的Connector，一个直接监听来自浏览器的http请求，一个监听来自其他WebServer的请求。</p><p>Coyote Http/1.1 Connector在端口8080上监听来自浏览器的http请求</p><p>Coyote AJP/1.3 Connector在端口8009上监听来自其他WebServer的servlet/jsp代理请求。</p></li><li><p>Engine</p><p>Engine下可以配置多个虚拟主机，每个虚拟主机都有一个域名，当Engine获得一个请求时，Engine会把该请求匹配到某个Host上，然后把该请求交给该Host来处理。</p><p>Engine有一个默认虚拟主机，当请求无法匹配到任何一个Host上的时候，将交给该默认Host来处理。</p></li><li><p>Host</p><p>代表一个虚拟主机，每个虚拟主机和某个网络域名相匹配。每个虚拟主机下都可以部署一个或者多个WebApp，每个WebApp对应于一个Context，有一个ContextPath。当Host获得一个请求时，将把该请求匹配到某个Context上，然后把该请求交给该Context来处理。匹配的方法是“最长匹配”，所以一个path==“”的Context将成为该Host的默认Context，所有无法和其他Context的路径名匹配的请求都将最终和该默认Context匹配。</p></li><li><p>Context</p><p>一个Context对应于一个Web Application（Web应用），一个Web应用有一个或多个Servlet组成，Context在创建的时候将根据配置文件\$CATALINA_HOME/conf/web.xml和\$WEBAPP_HOME/WEB-INF/web.xml载入Servlet类。如果找到，则执行该类，获得请求的回应，并返回。</p><p>Tomcat各组件关系图(此图来此网上)</p><p><img src="https://raw.githubusercontent.com/ArtIsLong/apache-tomcat-8.5.16-src/master/resources/images/tomcat-startup.gif" alt="QQ截图20170913174040"></p></li></ul><h3 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h3><h4 id="启动总体流程"><a href="#启动总体流程" class="headerlink" title="启动总体流程"></a>启动总体流程</h4><p>Tomcat里的Server由org.apache.catalina.startup.Catalina来管理，Catalina是整个Tomcat的管理类，它里面的三个方法load，start，stop分别用来管理整个服务器的生命周期，load方法用于根据conf/server.xml文件创建Server并调用Server的init方法进行初始化，start方法用于启动服务器，stop方法用于停止服务器，start和stop方法在内部分别调用了Server的start和stop方法，load方法内部调用了Server的init方法，这三个方法都会按容器的结构逐层调用相应的方法，比如，Server的start方法中会调用所有的Service中的start方法，Service中的start方法又会调用所有的Service中的start方法，Service中的start方法又会调用所有包含的Connectors和Container的start方法，这样这个服务器就启动了，init和stop方法也一样，这就是整个Tomcat的生命周期的管理方式。Catalina还有个await方法，await方法直接调用了Server的await方法，这个方法的作用是进入一个循环，让主线程不退出。</p><p>Tomcat的启动入口上面说过，是org.apache.catalina.startup.Bootstrap，作用类似于一个CatalinaAdaptor，具体的处理过程还是使用Catalina来完成的，这么做的好处是可以把启动的入口和具体的管理类分开，从而可以很方便的创建出多种启动方式，每种启动方式只需要写一个相应的CatalinaAdaptor就可以了。</p><p><img src="https://github.com/ArtIsLong/apache-tomcat-8.5.16-src/blob/master/resources/images/tomcat%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90.png?raw=true" alt="tomcat启动流程分析"></p><p><em>注：</em>图片比较模糊，如需查看清晰图片，请自行下载resources/images目录中的<strong>tomcat启动流程分析.png</strong> 或 resources/docs中的<strong>Tomcat源码分析.mdl</strong> ，使用Rational Rose等工具打开即可。</p><h4 id="启动流程详解"><a href="#启动流程详解" class="headerlink" title="启动流程详解"></a>启动流程详解</h4><p>正常情况下启动Tomcat，就是调用Bootstrap的main方法，代码如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String args[])</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (daemon == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="comment">// Don't set daemon until init() has completed</span></span><br><span class="line">            <span class="comment">// 初始化了ClassLoader，并用ClassLoader创建了Catalina实例，赋给catalinaDaemon变量</span></span><br><span class="line">            Bootstrap bootstrap = <span class="keyword">new</span> Bootstrap();</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                bootstrap.init();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Throwable t) &#123;</span><br><span class="line">                handleThrowable(t);</span><br><span class="line">                t.printStackTrace();</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            daemon = bootstrap;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// When running as a service the call to stop will be on a new</span></span><br><span class="line">            <span class="comment">// thread so make sure the correct class loader is used to prevent</span></span><br><span class="line">            <span class="comment">// a range of class not found exceptions.</span></span><br><span class="line">            Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            String command = <span class="string">"start"</span>;</span><br><span class="line">            <span class="keyword">if</span> (args.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                command = args[args.length - <span class="number">1</span>];</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (command.equals(<span class="string">"startd"</span>)) &#123;</span><br><span class="line">                args[args.length - <span class="number">1</span>] = <span class="string">"start"</span>;</span><br><span class="line">                daemon.load(args);</span><br><span class="line">                daemon.start();</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (command.equals(<span class="string">"stopd"</span>)) &#123;</span><br><span class="line">                args[args.length - <span class="number">1</span>] = <span class="string">"stop"</span>;</span><br><span class="line">                daemon.stop();</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (command.equals(<span class="string">"start"</span>)) &#123;</span><br><span class="line">                daemon.setAwait(<span class="keyword">true</span>);</span><br><span class="line">                daemon.load(args);</span><br><span class="line">                daemon.start();</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (command.equals(<span class="string">"stop"</span>)) &#123;</span><br><span class="line">                daemon.stopServer(args);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (command.equals(<span class="string">"configtest"</span>)) &#123;</span><br><span class="line">                daemon.load(args);</span><br><span class="line">                <span class="keyword">if</span> (<span class="keyword">null</span>==daemon.getServer()) &#123;</span><br><span class="line">                    System.exit(<span class="number">1</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                System.exit(<span class="number">0</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                log.warn(<span class="string">"Bootstrap: command \""</span> + command + <span class="string">"\" does not exist."</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable t) &#123;</span><br><span class="line">            <span class="comment">// Unwrap the Exception for clearer error reporting</span></span><br><span class="line">            <span class="keyword">if</span> (t <span class="keyword">instanceof</span> InvocationTargetException &amp;&amp;</span><br><span class="line">                    t.getCause() != <span class="keyword">null</span>) &#123;</span><br><span class="line">                t = t.getCause();</span><br><span class="line">            &#125;</span><br><span class="line">            handleThrowable(t);</span><br><span class="line">            t.printStackTrace();</span><br><span class="line">            System.exit(<span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>main方法中，首先执行init方法初始化了Tomcat自己的类加载器，并通过类加载器创建Catalina实例，然后赋给catalinaDaemon变量，后续操作都使用catalinaDaemon来执行。</p><p>后面默认执行start命令，将调用setAwait(true)，load(args)和start()这三个方法，这三个方法内部都通过反射调用了Catalina的相应方法。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// org.apache.catalina.startup.Catalina</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setAwait</span><span class="params">(<span class="keyword">boolean</span> b)</span> </span>&#123;</span><br><span class="line">    await = b;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>setAwait方法用于设置Server启动完成后是否进入等待状态的标志，如果为true则进入，否则不进入。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// org.apache.catalina.startup.Catalina</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">  * Start a new server instance.</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">load</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">long</span> t1 = System.nanoTime();</span><br><span class="line">    initDirs();</span><br><span class="line">    <span class="comment">// Before digester - it may be needed</span></span><br><span class="line">    initNaming();</span><br><span class="line">    <span class="comment">// Create and execute our Digester</span></span><br><span class="line">    Digester digester = createStartDigester();</span><br><span class="line">    InputSource inputSource = <span class="keyword">null</span>;</span><br><span class="line">    InputStream inputStream = <span class="keyword">null</span>;</span><br><span class="line">    File file = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            file = configFile();</span><br><span class="line">            inputStream = <span class="keyword">new</span> FileInputStream(file);</span><br><span class="line">            inputSource = <span class="keyword">new</span> InputSource(file.toURI().toURL().toString());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">          	<span class="keyword">if</span> (log.isDebugEnabled()) &#123;</span><br><span class="line">            	log.debug(sm.getString(<span class="string">"catalina.configFail"</span>, file), e);</span><br><span class="line">          	&#125;</span><br><span class="line">        &#125;</span><br><span class="line">      	<span class="keyword">if</span> (inputStream == <span class="keyword">null</span>) &#123;</span><br><span class="line">        	<span class="keyword">try</span> &#123;</span><br><span class="line">          		inputStream = getClass().getClassLoader().getResourceAsStream(getConfigFile());</span><br><span class="line">          		inputSource = <span class="keyword">new</span> InputSource(getClass().getClassLoader().getResource(getConfigFile()).toString());</span><br><span class="line">        	&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">          		<span class="keyword">if</span> (log.isDebugEnabled()) &#123;</span><br><span class="line">            		log.debug(sm.getString(<span class="string">"catalina.configFail"</span>,getConfigFile()), e);</span><br><span class="line">          		&#125;</span><br><span class="line">        	&#125;</span><br><span class="line">      	&#125;</span><br><span class="line">      	<span class="comment">// This should be included in catalina.jar</span></span><br><span class="line">      	<span class="comment">// Alternative: don't bother with xml, just create it manually.</span></span><br><span class="line">      	<span class="keyword">if</span> (inputStream == <span class="keyword">null</span>) &#123;</span><br><span class="line">        	<span class="keyword">try</span> &#123;</span><br><span class="line">          		inputStream = getClass().getClassLoader().getResourceAsStream(<span class="string">"server-embed.xml"</span>);</span><br><span class="line">          		inputSource = <span class="keyword">new</span> InputSource(getClass().getClassLoader().getResource(<span class="string">"server-embed.xml"</span>).toString());</span><br><span class="line">        	&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">          		<span class="keyword">if</span> (log.isDebugEnabled()) &#123;</span><br><span class="line">            		log.debug(sm.getString(<span class="string">"catalina.configFail"</span>,<span class="string">"server-embed.xml"</span>), e);</span><br><span class="line">          		&#125;</span><br><span class="line">        	&#125;	</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (inputStream == <span class="keyword">null</span> || inputSource == <span class="keyword">null</span>) &#123;</span><br><span class="line">        	<span class="keyword">if</span>  (file == <span class="keyword">null</span>) &#123;</span><br><span class="line">          		log.warn(sm.getString(<span class="string">"catalina.configFail"</span>,getConfigFile() + <span class="string">"] or [server-embed.xml]"</span>));</span><br><span class="line">        	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          		log.warn(sm.getString(<span class="string">"catalina.configFail"</span>,file.getAbsolutePath()));</span><br><span class="line">          		<span class="keyword">if</span> (file.exists() &amp;&amp; !file.canRead()) &#123;</span><br><span class="line">            		log.warn(<span class="string">"Permissions incorrect, read permission is not allowed on the file."</span>);</span><br><span class="line">          		&#125;</span><br><span class="line">        	&#125;</span><br><span class="line">        	<span class="keyword">return</span>;</span><br><span class="line">      	&#125;</span><br><span class="line">      	<span class="keyword">try</span> &#123;</span><br><span class="line">        	inputSource.setByteStream(inputStream);</span><br><span class="line">        	digester.push(<span class="keyword">this</span>);</span><br><span class="line">        	digester.parse(inputSource);</span><br><span class="line">      	&#125; <span class="keyword">catch</span> (SAXParseException spe) &#123;</span><br><span class="line">        	log.warn(<span class="string">"Catalina.start using "</span> + getConfigFile() + <span class="string">": "</span> + spe.getMessage());</span><br><span class="line">        	<span class="keyword">return</span>;</span><br><span class="line">      	&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        	log.warn(<span class="string">"Catalina.start using "</span> + getConfigFile() + <span class="string">": "</span> , e);</span><br><span class="line">        	<span class="keyword">return</span>;</span><br><span class="line">      	&#125;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">      	<span class="keyword">if</span> (inputStream != <span class="keyword">null</span>) &#123;</span><br><span class="line">        	<span class="keyword">try</span> &#123;</span><br><span class="line">          		inputStream.close();</span><br><span class="line">        	&#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">          	<span class="comment">// Ignore</span></span><br><span class="line">        	&#125;</span><br><span class="line">      	&#125;</span><br><span class="line">    &#125;</span><br><span class="line">  	getServer().setCatalina(<span class="keyword">this</span>);</span><br><span class="line">  	getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());</span><br><span class="line">  	getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());</span><br><span class="line">  	<span class="comment">// Stream redirection</span></span><br><span class="line">  	initStreams();</span><br><span class="line">  	<span class="comment">// Start the new server</span></span><br><span class="line">  	<span class="keyword">try</span> &#123;</span><br><span class="line">    	getServer().init();</span><br><span class="line">  	&#125; <span class="keyword">catch</span> (LifecycleException e) &#123;</span><br><span class="line">    	<span class="keyword">if</span> (Boolean.getBoolean(<span class="string">"org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"</span>)) &#123;</span><br><span class="line">      		<span class="keyword">throw</span> <span class="keyword">new</span> java.lang.Error(e);</span><br><span class="line">    	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      		log.error(<span class="string">"Catalina.start"</span>, e);</span><br><span class="line">    	&#125;</span><br><span class="line">  	&#125;</span><br><span class="line">  	<span class="keyword">long</span> t2 = System.nanoTime();</span><br><span class="line">  	<span class="keyword">if</span>(log.isInfoEnabled()) &#123;</span><br><span class="line">    	log.info(<span class="string">"Initialization processed in "</span> + ((t2 - t1) / <span class="number">1000000</span>) + <span class="string">" ms"</span>);</span><br><span class="line">  	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Catalina的load方法根据conf/server.xml创建了Server对象，并赋值给server属性（具体是通过开源项目Digester完成的），然后调用了server的init方法。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// org.apache.catalina.startup.Catalina</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">start</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  	<span class="keyword">if</span> (getServer() == <span class="keyword">null</span>) &#123;</span><br><span class="line">		load();</span><br><span class="line">	&#125;</span><br><span class="line">    <span class="keyword">if</span> (getServer() == <span class="keyword">null</span>) &#123;</span><br><span class="line">        log.fatal(<span class="string">"Cannot start server. Server instance is not configured."</span>);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">long</span> t1 = System.nanoTime();</span><br><span class="line">    <span class="comment">// Start the new server</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        getServer().start();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (LifecycleException e) &#123;</span><br><span class="line">        log.fatal(sm.getString(<span class="string">"catalina.serverStartFail"</span>), e);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            getServer().destroy();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (LifecycleException e1) &#123;</span><br><span class="line">            log.debug(<span class="string">"destroy() failed for failed Server "</span>, e1);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">long</span> t2 = System.nanoTime();</span><br><span class="line">    <span class="keyword">if</span>(log.isInfoEnabled()) &#123;</span><br><span class="line">        log.info(<span class="string">"Server startup in "</span> + ((t2 - t1) / <span class="number">1000000</span>) + <span class="string">" ms"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// Register shutdown hook</span></span><br><span class="line">    <span class="keyword">if</span> (useShutdownHook) &#123;</span><br><span class="line">        <span class="keyword">if</span> (shutdownHook == <span class="keyword">null</span>) &#123;</span><br><span class="line">            shutdownHook = <span class="keyword">new</span> CatalinaShutdownHook();</span><br><span class="line">        &#125;</span><br><span class="line">        Runtime.getRuntime().addShutdownHook(shutdownHook);</span><br><span class="line">        <span class="comment">// If JULI is being used, disable JULI's shutdown hook since</span></span><br><span class="line">        <span class="comment">// shutdown hooks run in parallel and log messages may be lost</span></span><br><span class="line">        <span class="comment">// if JULI's hook completes before the CatalinaShutdownHook()</span></span><br><span class="line">        LogManager logManager = LogManager.getLogManager();</span><br><span class="line">        <span class="keyword">if</span> (logManager <span class="keyword">instanceof</span> ClassLoaderLogManager) &#123;</span><br><span class="line">            ((ClassLoaderLogManager) logManager).setUseShutdownHook(<span class="keyword">false</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (await) &#123;</span><br><span class="line">        await();</span><br><span class="line">        stop();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里首先判断Server是否已经存在了，如果不存在则调用load方法来初始化Server，然后调用Server的start方法来启动服务器，最后注册了关闭钩子并根据await属性判断是否进入等待状态，之前我们已经将这里的await属性设置为true，所以需要进入等待状态。进入等待状态会调用await和stop两个方法，await方法会直接调用Server的await方法，Server的await方法内部会执行一个while循环，这样程序就停到了await方法，当await方法里的while循环退出时，就会执行stop方法，从而关闭服务器。</p><p>代码如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// org.apache.catalina.core.StandardServer</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">await</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">// Negative values - don't wait on port - tomcat is embedded or we just don't like ports</span></span><br><span class="line">    <span class="keyword">if</span>( port == -<span class="number">2</span> ) &#123;</span><br><span class="line">        <span class="comment">// undocumented yet - for embedding apps that are around, alive.</span></span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>( port==-<span class="number">1</span> ) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            awaitThread = Thread.currentThread();</span><br><span class="line">            <span class="keyword">while</span>(!stopAwait) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    Thread.sleep( <span class="number">10000</span> );</span><br><span class="line">                &#125; <span class="keyword">catch</span>( InterruptedException ex ) &#123;</span><br><span class="line">                    <span class="comment">// continue and check the flag</span></span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            awaitThread = <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// Set up a server socket to wait on</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        awaitSocket = <span class="keyword">new</span> ServerSocket(port, <span class="number">1</span>,InetAddress.getByName(address));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">        log.error(<span class="string">"StandardServer.await: create["</span> + address+ <span class="string">":"</span> + port+ <span class="string">"]: "</span>, e);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        awaitThread = Thread.currentThread();</span><br><span class="line">        <span class="comment">// Loop waiting for a connection and a valid command</span></span><br><span class="line">        <span class="keyword">while</span> (!stopAwait) &#123;</span><br><span class="line">            ServerSocket serverSocket = awaitSocket;</span><br><span class="line">            <span class="keyword">if</span> (serverSocket == <span class="keyword">null</span>) &#123;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// Wait for the next connection</span></span><br><span class="line">            Socket socket = <span class="keyword">null</span>;</span><br><span class="line">            StringBuilder command = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                InputStream stream;</span><br><span class="line">                <span class="keyword">long</span> acceptStartTime = System.currentTimeMillis();</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    socket = serverSocket.accept();</span><br><span class="line">                    socket.setSoTimeout(<span class="number">10</span> * <span class="number">1000</span>);  <span class="comment">// Ten seconds</span></span><br><span class="line">                    stream = socket.getInputStream();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (SocketTimeoutException ste) &#123;</span><br><span class="line">                    <span class="comment">// This should never happen but bug 56684 suggests that</span></span><br><span class="line">                    <span class="comment">// it does.</span></span><br><span class="line">                    log.warn(sm.getString(<span class="string">"standardServer.accept.timeout"</span>,</span><br><span class="line">                                Long.valueOf(System.currentTimeMillis() - acceptStartTime)), ste);</span><br><span class="line">                    <span class="keyword">continue</span>;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (AccessControlException ace) &#123;</span><br><span class="line">                    log.warn(<span class="string">"StandardServer.accept security exception: "</span> + ace.getMessage(), ace);</span><br><span class="line">                	<span class="keyword">continue</span>;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (stopAwait) &#123;</span><br><span class="line">                        <span class="comment">// Wait was aborted with socket.close()</span></span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    log.error(<span class="string">"StandardServer.await: accept: "</span>, e);</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// Read a set of characters from the socket</span></span><br><span class="line">                <span class="keyword">int</span> expected = <span class="number">1024</span>; <span class="comment">// Cut off to avoid DoS attack</span></span><br><span class="line">                <span class="keyword">while</span> (expected &lt; shutdown.length()) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (random == <span class="keyword">null</span>)</span><br><span class="line">                        random = <span class="keyword">new</span> Random();</span><br><span class="line">                    expected += (random.nextInt() % <span class="number">1024</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">while</span> (expected &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    <span class="keyword">int</span> ch = -<span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        ch = stream.read();</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                        log.warn(<span class="string">"StandardServer.await: read: "</span>, e);</span><br><span class="line">                        ch = -<span class="number">1</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="comment">// Control character or EOF (-1) terminates loop</span></span><br><span class="line">                    <span class="keyword">if</span> (ch &lt; <span class="number">32</span> || ch == <span class="number">127</span>) &#123;</span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    command.append((<span class="keyword">char</span>) ch);</span><br><span class="line">                    expected--;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                <span class="comment">// Close the socket now that we are done with it</span></span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">if</span> (socket != <span class="keyword">null</span>) &#123;</span><br><span class="line">                        socket.close();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                    <span class="comment">// Ignore</span></span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// Match against our command string</span></span><br><span class="line">            <span class="keyword">boolean</span> match = command.toString().equals(shutdown);</span><br><span class="line">            <span class="keyword">if</span> (match) &#123;                					            </span><br><span class="line">              	log.info(sm.getString(<span class="string">"standardServer.shutdownViaPort"</span>));</span><br><span class="line">	        <span class="keyword">break</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span></span><br><span class="line">                log.warn(<span class="string">"StandardServer.await: Invalid command '"</span> + command.toString() + <span class="string">"' received"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        ServerSocket serverSocket = awaitSocket;</span><br><span class="line">        awaitThread = <span class="keyword">null</span>;</span><br><span class="line">        awaitSocket = <span class="keyword">null</span>;</span><br><span class="line">        <span class="comment">// Close the server socket and return</span></span><br><span class="line">        <span class="keyword">if</span> (serverSocket != <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                serverSocket.close();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                <span class="comment">// Ignore</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="参考书籍"><a href="#参考书籍" class="headerlink" title="参考书籍"></a>参考书籍</h2><blockquote><p> <a href="链接：http://pan.baidu.com/s/1o7Zp1Q6 密码：c87j">看透springMvc源代码分析与实践.pdf</a></p></blockquote><h2 id="推荐博客"><a href="#推荐博客" class="headerlink" title="推荐博客"></a>推荐博客</h2><blockquote><p><a href="http://www.jianshu.com/p/4cdc422b269b" target="_blank" rel="noopener">解析XML之Digester</a></p></blockquote><hr><p>关注我的微信公众号：FramePower<br>我会不定期发布相关技术积累，欢迎对技术有追求、志同道合的朋友加入，一起学习成长！</p><hr><p><img src="https://artislong.oss-cn-hangzhou.aliyuncs.com/images/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B71.png" alt="微信公众号"></p><div class="reward"><div class="reward-button">赏 <span class="reward-code"><span class="alipay-code"><img class="alipay-img wdp-appear" src="/css/images/alipay.jpeg"></span> <span class="wechat-code"><img class="wechat-img wdp-appear" src="/css/images/Wechat.jpeg"></span></span></div><p class="reward-notice">如果文章对你有帮助，欢迎点击上方按钮打赏作者</p></div></div><footer class="article-footer"><div class="share-container"><div class="bdsharebuttonbox"> <a href="#" class="bds_more" data-cmd="more">分享到：</a> <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a> <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a> <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a> <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a> <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a></div><script>with(window._bd_share_config={common:{bdSnsKey:{},bdText:"",bdMini:"2",bdMiniList:!1,bdPic:"",bdStyle:"0",bdSize:"16"},share:{bdSize:16}},document)(getElementsByTagName("head")[0]||body).appendChild(createElement("script")).src="http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion="+~(-new Date/36e5)</script><style>.bdshare_popup_box{border-radius:4px;border:#e1e1e1 solid 1px}.bdshare-button-style0-16 .bds_more,.bdshare-button-style0-16 a{padding-left:20px;margin:6px 10px 6px 0}.bdshare_dialog_list a,.bdshare_popup_bottom a,.bdshare_popup_list a{font-family:'Microsoft Yahei'}.bdshare_popup_top{display:none}.bdshare_popup_bottom{height:auto;padding:5px}</style></div></footer></div><nav id="article-nav"> <a href="/2018/07/28/Activiti-23张表及7大服务详解/" id="article-nav-newer" class="article-nav-link-wrap"><strong class="article-nav-caption">上一篇</strong><div class="article-nav-title"> Activiti 23张表及7大服务详解</div></a> <a href="/2018/03/19/Tomcat架构介绍及配置分析/" id="article-nav-older" class="article-nav-link-wrap"><strong class="article-nav-caption">下一篇</strong><div class="article-nav-title">Tomcat源码分析之架构介绍及配置分析</div></a></nav></article><section id="comments"></section></section><aside id="sidebar"><div class="widget-wrap"><h3 class="widget-title">最新文章</h3><div class="widget"><ul id="recent-post" class=""><li><div class="item-thumbnail"><a href="/2019/07/14/SpringBoot完美整合Jfinal/" class="thumbnail"><span class="thumbnail-image thumbnail-none"></span></a></div><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/SpringBoot/">SpringBoot</a></p><p class="item-title"><a href="/2019/07/14/SpringBoot完美整合Jfinal/" class="title">SpringBoot完美整合Jfinal</a></p><p class="item-date"><time datetime="2019-07-14T15:32:31.000Z" itemprop="datePublished">2019-07-14 23:32:31</time></p></div></li><li><div class="item-thumbnail"><a href="/2019/06/27/SpringBoot集成Flowable-UI/" class="thumbnail"><span class="thumbnail-image thumbnail-none"></span></a></div><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/工作流/">工作流</a><i class="fas fa-angle-right"></i><a class="article-category-link" href="/categories/工作流/Flowable/">Flowable</a></p><p class="item-title"><a href="/2019/06/27/SpringBoot集成Flowable-UI/" class="title">SpringBoot集成Flowable UI</a></p><p class="item-date"><time datetime="2019-06-26T16:27:21.000Z" itemprop="datePublished">2019-06-27 00:27:21</time></p></div></li><li><div class="item-thumbnail"><a href="/2019/05/25/Flowable五个引擎及相关服务总结/" class="thumbnail"><span class="thumbnail-image thumbnail-none"></span></a></div><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/工作流/">工作流</a><i class="fas fa-angle-right"></i><a class="article-category-link" href="/categories/工作流/Flowable/">Flowable</a></p><p class="item-title"><a href="/2019/05/25/Flowable五个引擎及相关服务总结/" class="title">Flowable五个引擎及相关服务总结</a></p><p class="item-date"><time datetime="2019-05-25T15:43:07.000Z" itemprop="datePublished">2019-05-25 23:43:07</time></p></div></li><li><div class="item-thumbnail"><a href="/2019/03/01/微服务基础概念认知总结/" class="thumbnail"><span class="thumbnail-image thumbnail-none"></span></a></div><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/思考/">思考</a></p><p class="item-title"><a href="/2019/03/01/微服务基础概念认知总结/" class="title">微服务基础概念认知总结</a></p><p class="item-date"><time datetime="2019-03-01T15:17:33.000Z" itemprop="datePublished">2019-03-01 23:17:33</time></p></div></li><li><div class="item-thumbnail"><a href="/2019/03/01/Oracle-SQL优化总结/" class="thumbnail"><span class="thumbnail-image thumbnail-none"></span></a></div><div class="item-inner"><p class="item-category"><a class="article-category-link" href="/categories/Oracle/">Oracle</a></p><p class="item-title"><a href="/2019/03/01/Oracle-SQL优化总结/" class="title">Oracle SQL优化总结</a></p><p class="item-date"><time datetime="2019-03-01T07:30:47.000Z" itemprop="datePublished">2019-03-01 15:30:47</time></p></div></li></ul></div></div><div class="widget-wrap"><h3 class="widget-title">分类</h3><div class="widget"><ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Alibaba/">Alibaba</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Docker/">Docker</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Git/">Git</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java基础/">Java基础</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Nginx/">Nginx</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Oracle/">Oracle</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Redis/">Redis</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Shiro/">Shiro</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Spring/">Spring</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/SpringBoot/">SpringBoot</a><span class="category-list-count">7</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/SpringBoot/Shiro/">Shiro</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/Storm/">Storm</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Tomcat/">Tomcat</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Zookeeper/">Zookeeper</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/工作流/">工作流</a><span class="category-list-count">3</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/工作流/Activiti/">Activiti</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/工作流/Flowable/">Flowable</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/工具/">工具</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/开发工具框架/">开发工具框架</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/思考/">思考</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/服务器/">服务器</a><span class="category-list-count">1</span></li></ul></div></div><div class="widget-wrap"><h3 class="widget-title">归档</h3><div class="widget"><ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/07/">七月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/06/">六月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/05/">五月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/03/">三月 2019</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/02/">二月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/01/">一月 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/12/">十二月 2018</a><span class="archive-list-count">6</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/11/">十一月 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/08/">八月 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/07/">七月 2018</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/03/">三月 2018</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/02/">二月 2018</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/01/">一月 2018</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/12/">十二月 2017</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/10/">十月 2017</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/09/">九月 2017</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/06/">六月 2017</a><span class="archive-list-count">7</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/12/">十二月 2016</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/07/">七月 2016</a><span class="archive-list-count">1</span></li></ul></div></div><div class="widget-wrap"><h3 class="widget-title">标签</h3><div class="widget"><ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Alibaba/">Alibaba</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Docker/">Docker</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Git/">Git</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Idea/">Idea</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Jackson/">Jackson</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java基础/">Java基础</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Lombok/">Lombok</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Nginx/">Nginx</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Oracle/">Oracle</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Quartz/">Quartz</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Redis/">Redis</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Session/">Session</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Shiro/">Shiro</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Spring/">Spring</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/SpringBoot/">SpringBoot</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Storm/">Storm</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Swagger/">Swagger</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Tomcat/">Tomcat</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Zookeeper/">Zookeeper</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/前后端分离/">前后端分离</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/多数据源/">多数据源</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/工作流/">工作流</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/工具/">工具</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/开发工具框架/">开发工具框架</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/微服务/">微服务</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据库/">数据库</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/负载均衡/">负载均衡</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/集群/">集群</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/面试题/">面试题</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/项目架构/">项目架构</a><span class="tag-list-count">2</span></li></ul></div></div><div class="widget-wrap"><h3 class="widget-title">标签云</h3><div class="widget tagcloud"> <a href="/tags/Alibaba/" style="font-size:10px">Alibaba</a> <a href="/tags/Docker/" style="font-size:15px">Docker</a> <a href="/tags/Git/" style="font-size:10px">Git</a> <a href="/tags/Idea/" style="font-size:10px">Idea</a> <a href="/tags/Jackson/" style="font-size:10px">Jackson</a> <a href="/tags/Java基础/" style="font-size:17.5px">Java基础</a> <a href="/tags/Lombok/" style="font-size:10px">Lombok</a> <a href="/tags/Nginx/" style="font-size:15px">Nginx</a> <a href="/tags/Oracle/" style="font-size:10px">Oracle</a> <a href="/tags/Quartz/" style="font-size:10px">Quartz</a> <a href="/tags/Redis/" style="font-size:12.5px">Redis</a> <a href="/tags/Session/" style="font-size:10px">Session</a> <a href="/tags/Shiro/" style="font-size:12.5px">Shiro</a> <a href="/tags/Spring/" style="font-size:12.5px">Spring</a> <a href="/tags/SpringBoot/" style="font-size:20px">SpringBoot</a> <a href="/tags/Storm/" style="font-size:10px">Storm</a> <a href="/tags/Swagger/" style="font-size:12.5px">Swagger</a> <a href="/tags/Tomcat/" style="font-size:12.5px">Tomcat</a> <a href="/tags/Zookeeper/" style="font-size:10px">Zookeeper</a> <a href="/tags/前后端分离/" style="font-size:10px">前后端分离</a> <a href="/tags/多数据源/" style="font-size:10px">多数据源</a> <a href="/tags/工作流/" style="font-size:15px">工作流</a> <a href="/tags/工具/" style="font-size:10px">工具</a> <a href="/tags/开发工具框架/" style="font-size:15px">开发工具框架</a> <a href="/tags/微服务/" style="font-size:10px">微服务</a> <a href="/tags/数据库/" style="font-size:10px">数据库</a> <a href="/tags/负载均衡/" style="font-size:10px">负载均衡</a> <a href="/tags/集群/" style="font-size:10px">集群</a> <a href="/tags/面试题/" style="font-size:10px">面试题</a> <a href="/tags/项目架构/" style="font-size:12.5px">项目架构</a></div></div><div class="widget-wrap widget-list"><h3 class="widget-title">链接</h3><div class="widget"><ul><li> <a href="https://www.xiefayang.com">i蝸居年華_谢谢谢</a></li><li> <a href="http://fullsmilespace.com">微笑空间站</a></li></ul></div></div><div id="toTop" class="fas fa-angle-up"></div></aside></div><footer id="footer"><div class="outer"><div id="footer-info" class="inner"> &copy; 2020 ArtIsLong的博客<br> Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>. Theme by <a href="http://github.com/ppoffice">PPOffice</a></div></div><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></footer><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css"><script src="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js"></script><script>if(document.getElementById("comments")){var id=decodeURI(window.location.pathname),gitalk=new Gitalk({id:id,owner:"ArtIsLong",repo:"ArtIsLong.github.io",admin:["ArtIsLong"],clientID:"2f97f5d71dbb65bf01e1",clientSecret:"f715a8e1507c1fef1c5e3cfaccef8f59aa734318",distractionFreeMode:!0,createIssueManually:!1,perPage:15});gitalk.render("comments")}</script><script src="/libs/lightgallery/js/lightgallery.min.js"></script><script src="/libs/lightgallery/js/lg-thumbnail.min.js"></script><script src="/libs/lightgallery/js/lg-pager.min.js"></script><script src="/libs/lightgallery/js/lg-autoplay.min.js"></script><script src="/libs/lightgallery/js/lg-fullscreen.min.js"></script><script src="/libs/lightgallery/js/lg-zoom.min.js"></script><script src="/libs/lightgallery/js/lg-hash.min.js"></script><script src="/libs/lightgallery/js/lg-share.min.js"></script><script src="/libs/lightgallery/js/lg-video.min.js"></script><script src="/libs/justified-gallery/jquery.justifiedGallery.min.js"></script><script src="/js/main.js"></script></div><script>((window.gitter={}).chat={}).options={room:"artislong/Lobby"}</script><script src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer="defer"></script><script type="text/javascript" color="0,0,255" opacity="0.7" zindex="-2" count="99" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script><script async custom-element="amp-auto-ads" src="https://cdn.ampproject.org/v0/amp-auto-ads-0.1.js"></script></body>